<?php
/**
 * Description: 有赞商品
 * Author: hezhizheng
 * Date: 2018/7/13
 * Time: 15:25
 * Created by Created by Panxsoft.
 */

namespace App\Services\Youzan;

use App\Exceptions\ApiErrCode;
use App\Exceptions\ApiException;
use App\Models\Panx\Product;
use App\Models\Panx\ProductImage;
use App\Models\Store\Store;
use App\Models\Youzan\YouzanAuthorizer;
use App\Services\Utils\Guard;
use App\Services\Utils\Transaction;
use Carbon\Carbon;

class ProductRepository
{
    protected $youzanApp;

    public function __construct()
    {
        $this->youzanApp = new AppFactory;
    }

    /**
     * 获取出售中的商品列表
     *
     * @param YouzanAuthorizer $youzanAuthorizer
     * @param array $params
     * @return array
     * @throws ApiException
     * @throws \App\Exceptions\ApiSilentException
     * @throws \Throwable
     */
    public function getItemsOnSale(YouzanAuthorizer $youzanAuthorizer, array $params = [])
    {
        // 创建授权应用
        $authorYouzan = $this->youzanApp->getAuthorYouzan($youzanAuthorizer);

        try {
            $result = $authorYouzan->request(AppFactory::YOUZAN_ITEMS_ONSALE_GET, $params);
        } catch (\Exception $exception) {
            throw new ApiException(ApiErrCode::YOUZAN_ERROR, $exception->getMessage());
        }

        return $result;
    }


    /**
     *
     * 获取仓库中的商品列表
     *
     * @param YouzanAuthorizer $youzanAuthorizer
     * @param array $params
     * @return array
     * @throws ApiException
     * @throws \App\Exceptions\ApiSilentException
     * @throws \Throwable
     */
    public function getItemsInventory(YouzanAuthorizer $youzanAuthorizer, array $params = [])
    {
        // 创建授权应用
        $authorYouzan = $this->youzanApp->getAuthorYouzan($youzanAuthorizer);

        try {
            $result = $authorYouzan->request(AppFactory::YOUZAN_ITEMS_INVENTORY_GET, $params);
        } catch (\Exception $exception) {
            throw new ApiException(ApiErrCode::YOUZAN_ERROR,$exception->getMessage());
        }


        return $result;
    }

    /**
     *
     * @test
     *
     * @param YouzanAuthorizer $youzanAuthorizer
     * @param array $items_params
     *
     * @see assembleItemsParams
     *
     * @return array
     *
     * @throws \Exception
     * @throws \Throwable
     */
    public function getAllItemsOnSale(YouzanAuthorizer $youzanAuthorizer,
                                      array $items_params): array
    {
        $params = $items_params;
        $start_page = $last_page = $params['page_no'];
        $per_page = $params['page_size'];

        $products = [];
        for ($cur_page = $start_page; $cur_page <= $last_page; $cur_page++) {
            $on_sale_products = $this->getItemsOnSale($youzanAuthorizer, $params);

            $products = array_merge($products, $on_sale_products['items']);

            if ($start_page === $last_page) { // recalculate total page if is the first request
                $last_page = (int) (ceil($on_sale_products['count'] / $per_page));
            }

            $params['page_no']++;
        }

        return $products;
    }

    /**
     * @param int $page_no - 页数
     * @param int $page_size - 每页返回数量
     *
     * @return array
     */
    public function assembleItemsParams(int $page_no = 1,
                                        int $page_size = 100): array
    {
        return [
            'page_no'       => $page_no,
            'page_size'     => $page_size,
        ];
    }

    /**
     *
     * @test
     * @param YouzanAuthorizer $youzanAuthorizer
     * @param array $items_params
     *
     * @see assembleItemsParams
     *
     * @return array
     *
     * @throws \Exception
     * @throws \Throwable
     */
    public function getAllItemsInventory(YouzanAuthorizer $youzanAuthorizer,
                                         array $items_params): array
    {
        $params = $items_params;
        $start_page = $last_page = $params['page_no'];
        $per_page = $params['page_size'];

        $products = [];
        for ($cur_page = $start_page; $cur_page <= $last_page; $cur_page++) {
            $on_sale_products = $this->getItemsInventory($youzanAuthorizer, $params);

            $products = array_merge($products, $on_sale_products['items']);

            if ($start_page === $last_page) { // recalculate total page if is the first request
                $last_page = (int) (ceil($on_sale_products['count'] / $per_page));
            }

            $params['page_no']++;
        }

        return $products;
    }

    /**
     * @param  array $transformItems 格式化的商品数据
     * @param  array $list 带格式化的商品数据
     * @return mixed|bool
     * @throws \Exception
     */
    public function syncProducts(array $transformItems, array $list)
    {
        $store_id = Guard::storeAdmin()->store_id ?? Product::NO_STORE_ID;

        $customer_id = Guard::customerAdmin()->customer_id ?? Guard::store()->customer_id;

        $insert = Transaction::handle(function () use ($transformItems, $list, $store_id, $customer_id) {
            // 先同步商品数据, 再同步缩略图
            foreach ($transformItems as $transformItem) {
                $image = $transformItem['image'];
                unset($transformItem['image']);

                /** @var Product $product */
                $product = (new Product)->updateOrCreate(
                    [
                        'youzan_item_id' => $transformItem['youzan_item_id'], //  商家跟店铺可以授权给同一家有赞店铺
                        'customer_id'    => $customer_id,
                        'store_id'       => $store_id
                    ], $transformItem);

                // 保存商品图片信息
                $this->updateOrCreateThumb($product, $image);
            }

            return true;
        });

        return $insert;
    }

    /**
     * @param Product $product
     * @param $image
     * @return array|\Illuminate\Database\Eloquent\Model
     */
    private function updateOrCreateThumb(Product $product, $image)
    {
        $product_image_data = [
            'product_id' => $product->id,
            'type'       => ProductImage::TYPE_THUMB,
            'key'        => $image,
            'created_at' => Carbon::now(),
            'updated_at' => Carbon::now(),
        ];

        $product_image = (new ProductImage)->updateOrCreate([
                'product_id' => $product->id,
                'type'       => ProductImage::TYPE_THUMB,
            ], $product_image_data);

        return $product_image;
    }
}